from PyQt5.Qt import *
import requests
import base64
import json
import os
from urllib.parse import unquote, quote
import re
import time


class Config(object):
    @staticmethod
    def get_city_file_path():
        current_path = os.path.realpath(__file__)
        current_dic = os.path.split(current_path)[0]
        return current_dic + r"\city.json"


class TimeTool(object):
    @staticmethod
    def get_train_format_date(train_date):
        date_arr = time.strptime(train_date, "%Y%m%d")
        time_tamp = time.mktime(date_arr)
        time_local = time.localtime(time_tamp)
        format_date = "%a %b %d %Y %H:%M:%S GMT+0800 (中国标准时间)"
        return time.strftime(format_date, time_local)


class API(object):
    # 获取验证码
    GET_YZM_URL = "https://kyfw.12306.cn/passport/captcha/captcha-image64"

    # 校验账号密码
    CHECK_USERNAME_PASSWORD_URL = "https://kyfw.12306.cn/passport/web/login"

    # 获取滑动验证码
    GET_SLIDE_PASSCODE_URL = "https://kyfw.12306.cn/passport/web/slide-passcode"

    # 登录
    LOGIN_URL = "https://kyfw.12306.cn/otn/index/initMy12306Api"

    # 查询车票
    SELECT_TICKET = "https://kyfw.12306.cn/otn/leftTicket/queryT"

    # 获取所有城市
    ALL_CITY_URL = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js?station_version=1.9162"

    # 校验用户信息
    CHECK_USER_URL = "https://kyfw.12306.cn/otn/login/checkUser"

    # 提交订单
    SUBMIT_ORDER = "https://kyfw.12306.cn/otn/leftTicket/submitOrderRequest"

    # 获取联系人信息
    GET_PASSENGER = "https://kyfw.12306.cn/otn/confirmPassenger/getPassengerDTOs"

    # 校验订单
    CHECK_ORDER = "https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo"

    QUEUE_COUNT = "https://kyfw.12306.cn/otn/confirmPassenger/getQueueCount"

    CONFIRM_QUEUE = "https://kyfw.12306.cn/otn/confirmPassenger/confirmSingleForQueue"

    WAIT_TIME = "https://kyfw.12306.cn/otn/confirmPassenger/queryOrderWaitTime"

    RESULT_ORDER = "https://kyfw.12306.cn/otn/confirmPassenger/resultOrderForDcQueue"

    INIT_URL = "https://kyfw.12306.cn/otn//payOrder/init"

    headers_tk = {
        "cookie": "JSESSIONID=6AE1720AE52BD763BA010522B6F7387E; tk=_BubHUMDDSUC83ce4R4YKbkXfUDSnFfJIZz2trAaeAI09q1q0; _jc_save_wfdc_flag=dc; _jc_save_fromStation=%u91CD%u5E86%2CCUW; _jc_save_toStation=%u5317%u4EAC%u5317%2CBXP; BIGipServerotn=1022362122.50210.0000; BIGipServerpool_passport=48497162.50215.0000; RAIL_EXPIRATION=1610769164907; RAIL_DEVICEID=QVCbAzrBQH0kDTJ4us_NXsopfwc3mnRQEP9JdwQTdz128EUa0orKGDD701PytuX12H1w6WWCCWKmaLQegaZOVaENg8D4o9yYEOR49NIwlZu580gSWyQrJrJVgbeYUeFIcP3sVU4KA3zdl5WQ6tmdq-y-xAhWcn4L; route=6f50b51faa11b987e576cdb301e545c4; uKey=fd7f703d1a3c8ec2f195157836c680a221e471274456d13b55c01b2f1a74f447; current_captcha_type=Z; _jc_save_fromDate=2021-01-12; _jc_save_toDate=2021-01-12"
    }


class APITools(QObject):
    session = requests.session()

    @classmethod
    def download_yzm(cls):
        params = {
            "login_site": "E",
            "module": "login",
            "rand": "sjrand",
            "1603245923296": "",
            "callback": "jQuery191010441538270166206_1603245907686",
            "_": "1603245907691"
        }
        response = cls.session.get(API.GET_YZM_URL, params=params)
        url = response.text
        split = url.split("\"")
        split = split[3:4]
        split = ''.join(split)
        img_data = base64.b64decode(split)
        with open("API/yzm.jpg", "wb") as f:
            f.write(img_data)
        return "API/yzm.jpg"

    @classmethod
    def check_yzm(cls, coordinate):
        new_coordinate = coordinate.replace(",", "%2C")
        check_url = "https://kyfw.12306.cn/passport/captcha/captcha-check?answer=" + new_coordinate + "&rand=sjrand&login_site=E"
        response = cls.session.get(check_url)
        check_url = response.text
        dic = json.loads(check_url)
        return dic["result_code"] == "4"

    @classmethod
    def get_slide_passcode(cls, username):
        data_dic = {
            "appid": "otn",
            "username": username,
            "slideMode": "480"
        }
        headers = {
            "cookie": "RAIL_DEVICEID=WH01izUc8nbsNgdmrsRxbgVB6HpHyPmazJWe_H3Bve4j4P0Hh68fNM-fx3ACKMnqbfhRjLzn5uxR7Qn-FOxAekAsI4vCE1TeWa9fNWn4LCAWIbcxM8Dd27Hnz1XawW6QSVktFMUSKTxOWd1AB1Hdtial1zL5Eotj;"}
        response = cls.session.post(API.GET_SLIDE_PASSCODE_URL, data=data_dic)
        print(response.text)
        return response.json()["if_check_slide_passcode_token"]

    @classmethod
    def check_username_password(cls, username, password, passcode):
        data_dic = {
            "sessionId": "010B3TrWzwsdkM2Lqh18cIU2tyPNSLIKRqgPt65SAUfXYgh4gowOt0Cd8xm3tk9lAb0ceSvCVY_9bj0uf8h-ahptILksAsi_jOiYiArUQCcwdB868MvOl8tcUwL1pP4Cne2szvnGd8ZAjZbFE47jpZETU0wdzhElJBSifjkq5xL1sD__dtCMGZHf3esgDC5g6EnALcbseNIzyI6tVyQ-jUIA",
            "sig": "05XqrtZ0EaFgmmqIQes-s-CEZZkDJcUj80AKSnBK_qX6gixlHVW1kiwI8rZRP9M0BOVW6bmZopM2fs5yeooG6BKC3ImpAh5pCyuTL-0MPg4i9c61lO4c5xF4cmdomh5dU68uSA37IIsnhl1NQA2vMy-4-J-yCYg2CIsHkAjWIkLVW1PnxgcJhJPRaY3AeyN4lE-3dDDJ3PQCA2jum_ZxjVxgOGH7iQMb3IWFKQPAuxq4WJ5qhY_MrcYaNOV0HVaB0v01Ar3YahFiLVfGqfBS59zpsjCQlnKJCzqrnkGRuvb8wRCChsAkz3rVTB7aHExzCQ7e2HI-_tVb0M_W751A_oMYXNodo3BDfQ2rIQz0-JKqUmSVcjDa3JjWQ1E6Y5k9oB2dD6y5WR32sT_wdC0wSq0T0ZFS1mz4z4HP5D9PkHdQRYGex7F7axPLPncsmaNhd_NOdpjSRbGddf8l-ZHnIvlVyJVUWK6BgIqFl0wrfPGCA",
            "tk": "",
            "username": username,
            "password": "@pJYTUTLyDImhcgXhWRMS7Q==",
            "appid": "otn",
            "scene": "nc_login",
            "if_check_slide_passcode_token": passcode
        }
        data = {
            "data": "106!N/xmc0clP2EHgvoFjmQI6Pc1xC/bnSfFHc0QPKUUz+H0n/6352amwGj3f4GpCxHmnlOLQnzfIux6XaB08S7lwqmMXxw5gOSAiHnOaYHDPJJWMreRfGQG8p+LDkQkEnFOlkNBXHU3XQP1rceqqZcMHxhelrHzhULXWd3GL0mgcf61O4rkysYJPfogzRFPs7OjXnrmqYckoRhV2GrixTYJSHq1mRGwE0v6s+eUmu8Hs+wnkQ2sxvOP1YUjpFUJx7sKsPoU5u8/s+G0mfenlxRzx+lIQw+QCEYGyZJA7SA+ef5Acqx0owUp4OpmfnuAoHbVmlj0IvyCND5YZyO2tZYxv0rLlpudabCwaGHW1r4UqeL1Ok100mIoNNO5B0nXPnUoqKk/KJsSx2q/i9+kyU2woqJDPmncjIZObDLCq1TndzMAyMn0rWYzdEp1yx0ipOuY1Nxf4a/3n3YWQdjkybS6Bcp1GleZxqwXexm/XNnxjqmftEnPQg/HbIPiHrwFAGjkx0Cb8zteCdyOyHjWu+iAK4Ro2V9ljVsb8+AX/tX4M2dK+faxa7uvhDy64ykRreL8cviC0FtCUw4EijoEojPr854ADKWG/nWn6YNAQOWZ0MqsCK1QWzEtS86T5cFpNYgRbxC8EVQvYsqnqUAIDrafhDHTxC/5BVDEsm12L3Sutan0XIIweY2d1nJp0qPyKdhReZ6wE0lh9/xzMn48y+Q1J4VTm1VZZeVd2ZXe743cT+p3uqb32y2p15e1xUF2OwILDwWDa4zazjZVBqW3WxPwWP5ojnr2cfEx2sdPaCVVRm8s5dgIvmpO8abQalExalWm8l8grkF6pBmrycv883SmeWvbgUnqFiOc0pPm0AIp9noPc+Ij/r/aoP9vjivaQdKaND/yIPki4ZzNq0==",
            "xa": "FFFF0N000000000097AD",
            "xt": "",
            "efy": "1"
        }
        url = "https://ynuf.aliapp.org/service/um.json"
        res = cls.session.post(url, data=data)
        print(res.text)
        headers = {
            "cookie": "RAIL_DEVICEID=WH01izUc8nbsNgdmrsRxbgVB6HpHyPmazJWe_H3Bve4j4P0Hh68fNM-fx3ACKMnqbfhRjLzn5uxR7Qn-FOxAekAsI4vCE1TeWa9fNWn4LCAWIbcxM8Dd27Hnz1XawW6QSVktFMUSKTxOWd1AB1Hdtial1zL5Eotj;"}
        response = cls.session.post(API.CHECK_USERNAME_PASSWORD_URL, data=data_dic)
        print(response.text)

    @classmethod
    def login(cls):
        response = cls.session.post(API.LOGIN_URL, headers=API.headers_tk)
        print(response.text)
        dic = response.json()
        return "龙" + dic["data"]["user_regard"]

    @classmethod
    def query_ticket(cls, train_date, from_station, to_station):
        # response = cls.session.post(API.LOGIN_URL, headers=API.headers_tk)
        # print(response.text)
        params = {
            "leftTicketDTO.train_date": train_date,
            "leftTicketDTO.from_station": from_station,
            "leftTicketDTO.to_station": to_station,
            "purpose_codes": "ADULT"
        }
        resp = cls.session.get(API.SELECT_TICKET, params=params, headers=API.headers_tk)
        result = resp.json()
        items = result["data"]["result"]
        print(items)
        reverse_city = APITools.get_all_city_reverse()
        train_dics = []
        for item in items:
            train_dic = {}
            train_info = item.split('|')
            train_dic['secret_str'] = train_info[0]
            train_dic['train_num'] = train_info[2]
            train_dic['train_name'] = train_info[3]
            train_dic['from_station_code'] = train_info[6]
            train_dic['to_station_code'] = train_info[7]
            train_dic['from_station_name'] = reverse_city[train_info[6]]
            train_dic['to_station_name'] = reverse_city[train_info[7]]
            train_dic['start_time'] = train_info[8]
            train_dic['arrive_time'] = train_info[9]
            train_dic['total_time'] = train_info[10]
            train_dic['left_ticket'] = train_info[12]
            train_dic['train_date'] = train_info[13]
            train_dic['train_location'] = train_info[15]
            train_dic['vip_soft_bed'] = train_info[21]
            train_dic['other_seat'] = train_info[22]
            train_dic['soft_bed'] = train_info[23]
            train_dic['no_seat'] = train_info[26]
            train_dic['hard_bed'] = train_info[28]
            train_dic['hard_seat'] = train_info[29]
            train_dic['second_seat'] = train_info[30]
            train_dic['first_seat'] = train_info[31]
            train_dic['business_seat'] = train_info[32]
            train_dics.append(train_dic)
        return train_dics

    @classmethod
    def buying_tickets(cls, reverse_city, params, row):
        resp = cls.session.get(API.SELECT_TICKET, params=params, headers=API.headers_tk)
        print(resp.text)
        result = resp.json()
        items = result["data"]["result"]
        train_dic = {}
        item = items[row]
        print(item)
        train_info = item.split('|')
        second_seat_info = train_info[30]
        print(second_seat_info)
        if isinstance(second_seat_info, str):
            if train_info[30] == "有":
                train_dic['secret_str'] = train_info[0]
                train_dic['train_num'] = train_info[2]
                train_dic['train_name'] = train_info[3]
                train_dic['from_station_code'] = train_info[6]
                train_dic['to_station_code'] = train_info[7]
                train_dic['start_time'] = train_info[8]
                train_dic['arrive_time'] = train_info[9]
                train_dic['from_station_name'] = reverse_city[train_info[6]]
                train_dic['to_station_name'] = reverse_city[train_info[7]]
                train_dic['total_time'] = train_info[10]
                train_dic['left_ticket'] = train_info[12]
                train_dic['train_date'] = train_info[13]
                train_dic['train_location'] = train_info[15]
                train_dic['vip_soft_bed'] = train_info[21]
                train_dic['other_seat'] = train_info[22]
                train_dic['soft_bed'] = train_info[23]
                train_dic['no_seat'] = train_info[26]
                train_dic['hard_bed'] = train_info[28]
                train_dic['hard_seat'] = train_info[29]
                train_dic['second_seat'] = train_info[30]
                train_dic['first_seat'] = train_info[31]
                train_dic['business_seat'] = train_info[32]
                return train_dic
            else:
                return None
        elif isinstance(second_seat_info, int):
            if train_info[30] > 0:
                train_dic['secret_str'] = train_info[0]
                train_dic['train_num'] = train_info[2]
                train_dic['train_name'] = train_info[3]
                train_dic['from_station_code'] = train_info[6]
                train_dic['to_station_code'] = train_info[7]
                train_dic['start_time'] = train_info[8]
                train_dic['arrive_time'] = train_info[9]
                train_dic['from_station_name'] = reverse_city[train_info[6]]
                train_dic['to_station_name'] = reverse_city[train_info[7]]
                train_dic['total_time'] = train_info[10]
                train_dic['left_ticket'] = train_info[12]
                train_dic['train_date'] = train_info[13]
                train_dic['train_location'] = train_info[15]
                train_dic['vip_soft_bed'] = train_info[21]
                train_dic['other_seat'] = train_info[22]
                train_dic['soft_bed'] = train_info[23]
                train_dic['no_seat'] = train_info[26]
                train_dic['hard_bed'] = train_info[28]
                train_dic['hard_seat'] = train_info[29]
                train_dic['second_seat'] = train_info[30]
                train_dic['first_seat'] = train_info[31]
                train_dic['business_seat'] = train_info[32]
                return train_dic
            else:
                return None
        else:
            return None

    @classmethod
    def check_user(cls):
        resp = cls.session.post(API.CHECK_USER_URL, data={"_json_att": ""}, headers=API.headers_tk)
        print("check_user" + resp.text)

    @classmethod
    def submit(cls, train_dic):
        train_date = train_dic["train_date"]
        data_dic = {
            "secretStr": unquote(train_dic["secret_str"]),
            "train_date": train_date[0:4] + "-" + train_date[4:6] + "-" + train_date[6:8],
            "back_train_date": train_date[0:4] + "-" + train_date[4:6] + "-" + train_date[6:8],
            "tour_flag": "dc",
            "purpose_codes": "ADULT",
            "query_from_station_name": train_dic["from_station_name"],
            "query_to_station_name": train_dic["to_station_name"],
            "undefined": ""
        }
        resp = cls.session.post(API.SUBMIT_ORDER, data=data_dic, headers=API.headers_tk)
        print("submit->" + resp.text)

    @classmethod
    def init_dc(cls):
        resp = cls.session.post("https://kyfw.12306.cn/otn/confirmPassenger/initDc", data={"_json_att": ""},
                                headers=API.headers_tk)
        token = re.findall(r"var globalRepeatSubmitToken = '(.*?)'", resp.text)[0]
        key_check_is_change = re.findall(r"'key_check_isChange':'(.*?)'", resp.text)[0]
        print("init_dc" + token)
        return token, key_check_is_change

    @classmethod
    def get_passenger(cls, token):
        data_dic = {
            "_json_att": "",
            "REPEAT_SUBMIT_TOKEN": token
        }
        resp = cls.session.post(API.GET_PASSENGER, data=data_dic, headers=API.headers_tk)
        passengers = resp.json()["data"]["normal_passengers"]
        for item in passengers:
            name = item["passenger_name"]
            if name == "龙李军":
                print(item)
                return item

    @classmethod
    def check_order(cls, passengers, token, seat_type=None):
        data_dic = {
            "cancel_flag": "2",
            "bed_level_order_num": "000000000000000000000000000000",
            "passengerTicketStr": "{},{},{},{},{},{},{},N,{}".format("O", passengers["passenger_flag"],
                                                                     passengers["passenger_type"],
                                                                     passengers["passenger_name"],
                                                                     passengers["passenger_id_type_code"],
                                                                     passengers["passenger_id_no"],
                                                                     passengers["mobile_no"], passengers["allEncStr"]),
            "oldPassengerStr": "{},{},{},1_".format(passengers["passenger_name"], passengers["passenger_id_type_code"],
                                                    passengers["passenger_id_no"]),
            "tour_flag": "dc",
            "randCode": "",
            "whatsSelect": "1",
            "sessionId": "",
            "sig": "",
            "scene": "nc_login",
            "_json_att": "",
            "REPEAT_SUBMIT_TOKEN": token
        }
        print("check_order")
        print(data_dic)
        resp = cls.session.post(API.CHECK_ORDER, data=data_dic, headers=API.headers_tk)
        print("check_order" + resp.text)

    @classmethod
    def queue_count(cls, train_dic, token):
        data_dic = {
            "train_date": TimeTool.get_train_format_date(train_dic["train_date"]),
            "train_no": train_dic["train_num"],
            "stationTrainCode": train_dic["train_name"],
            "seatType": "O",
            "fromStationTelecode": train_dic["from_station_code"],
            "toStationTelecode": train_dic["to_station_code"],
            "leftTicket": train_dic["left_ticket"],
            "purpose_codes": "00",
            "train_location": train_dic["train_location"],
            "_json_att": "",
            "REPEAT_SUBMIT_TOKEN": token
        }
        print("queue_count")
        print(data_dic)
        resp = cls.session.post(API.QUEUE_COUNT, data=data_dic, headers=API.headers_tk)
        print("queue_count" + resp.text)

    @classmethod
    def confirm_queue(cls, passengers, train_dic, token, key_check_is_change, seat_type=None):
        data_dic = {
            "passengerTicketStr": "{},{},{},{},{},{},{},N,{}".format("O", passengers["passenger_flag"],
                                                                     passengers["passenger_type"],
                                                                     passengers["passenger_name"],
                                                                     passengers["passenger_id_type_code"],
                                                                     passengers["passenger_id_no"],
                                                                     passengers["mobile_no"], passengers["allEncStr"]),
            "oldPassengerStr": "{},{},{},1_".format(passengers["passenger_name"], passengers["passenger_id_type_code"],
                                                    passengers["passenger_id_no"]),
            "randCode": "",
            "purpose_codes": "00",
            "key_check_isChange": key_check_is_change,
            "leftTicketStr": train_dic["left_ticket"],
            "train_location": train_dic["train_location"],
            "choose_seats": "",
            "seatDetailType": "000",
            "whatsSelect": "1",
            "roomType": "00",
            "dwAll": "N",
            "_json_att": "",
            "REPEAT_SUBMIT_TOKEN": token
        }
        print("confirm_queue")
        print(data_dic)
        resp = cls.session.post(API.CONFIRM_QUEUE, data=data_dic, headers=API.headers_tk)
        print("confirm_queue" + resp.text)

    @classmethod
    def query_order(cls, token):
        # while True:
        t = int(time.time())
        random = str(t)
        params = {
            "tourFlag": "dc",
            "_json_att": "",
            "REPEAT_SUBMIT_TOKEN": token
        }
        resp = cls.session.get(API.WAIT_TIME, params=params, headers=API.headers_tk)
        print("query_order" + resp.text)
        order_id = resp.json()["data"]["orderId"]
        print(order_id)
        # if order_id is not None and order_id != '':
        return order_id

    @classmethod
    def sequence_no(cls, token):
        data_dic = {
            "_json_att": "",
            "REPEAT_SUBMIT_TOKEN": token
        }
        t = int(time.time())
        s = str(t)
        params = {
            "random": s
        }
        # url = API.INIT_URL + "?random=" + str(t)
        print(cls.session.cookies)
        resp = cls.session.post(API.INIT_URL, params=params, data=data_dic, headers=API.headers_tk)
        print("sequence_no" + resp.text)
        sequence_no = re.findall(r"var sequence_no = '(.*?)'", resp.text)[0]
        print("sequence_no->" + sequence_no)
        return sequence_no

    @classmethod
    def result_order(cls, token, sequence_no):
        data_dic = {
            "orderSequence_no": sequence_no,
            "_json_att": "",
            "REPEAT_SUBMIT_TOKEN": token
        }
        resp = cls.session.post(API.RESULT_ORDER, data=data_dic, headers=API.headers_tk)
        print(resp.text)

    @staticmethod
    def get_all_city_reverse():
        dic = APITools.get_all_city()
        reverse_dic = {value: key for key, value in dic.items()}
        return reverse_dic

    @staticmethod
    def get_all_city():
        if os.path.exists(Config.get_city_file_path()):
            print("读取缓存")
            with open(Config.get_city_file_path(), "r", encoding="utf-8") as f:
                result = json.loads(f.read(), encoding="utf-8")
                return result
        else:
            resp = requests.get(API.ALL_CITY_URL)
            city_dic = {}
            items = resp.text.split("@")
            for item in items:
                city_list = item.split("|")
                if len(city_list) != 6:
                    continue
                code = city_list[2]
                name = city_list[1]
                city_dic[name] = code
            print("下载城市信息")
            with open(Config.get_city_file_path(), "w", encoding="utf-8") as f:
                json.dump(city_dic, f)
            return city_dic


if __name__ == '__main__':
    i = 0
    while True:
        if i > 5:
            break
        else:
            print(i)
            i += 1
    print("出")


